package com.quwan.app.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.quwan.app.service.PrePaymentInterface;
import com.quwan.app.service.ProductCategoryService;
import com.quwan.app.vo.BalanceOrderByDate;
import com.quwan.app.vo.pay.PrePayParams;
import com.quwan.app.vo.pay.PrePayment;
import com.quwan.app.vo.pay.WxPrePayment;
import com.quwan.common.BaseController;
import com.quwan.common.Check;
import com.quwan.common.enums.BalanceLogEnum;
import com.quwan.common.enums.CommonStatus;
import com.quwan.common.enums.PaymentEnum;
import com.quwan.common.exception.ExpCode;
import com.quwan.common.result.ApiResult;
import com.quwan.common.result.PageResult;
import com.quwan.component.ComponentFactory;
import com.quwan.config.yml.OssConfig;
import com.quwan.constans.AppConst;
import com.quwan.entity.*;
import com.quwan.mapper.*;
import com.quwan.utils.DateUtils;
import com.quwan.utils.PayUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;


/**
 * @author quan
 * @date 2021-07-30 11:15
 */
@Api(tags = "充值接口")
@RestController
@RequestMapping("app/recharge")
@RequiredArgsConstructor
@Validated
public class RechargeController extends BaseController {
    private final TMemberBalanceLogMapper memberBalanceLogMapper;
    private final TVipRuleMapper vipRuleMapper;
    private final TRechargeVipMapper rechargeVipMapper;
    private final ProductCategoryService categoryService;
    private final TPublishOrderMapper publishOrderMapper;
    private final C2cOrderItemMapper orderItemMapper;
    private final C2cOrderMapper c2cOrderMapper;
    private final ComponentFactory componentFactory;
    private final TMemberMapper memberMapper;
    private final TDispatchOrderMapper dispatchOrderMapper;
    private final OssConfig ossConfig;


    @ApiOperation("余额变更列表")
    @PostMapping("log")
    public ApiResult<PageResult<BalanceOrderByDate>> balanceLog(HttpServletRequest request,
                                                                @RequestParam(defaultValue = "1") int pageNo,
                                                                @RequestParam(defaultValue = "10") int pageSize) {
        Page<TMemberBalanceLog> res = memberBalanceLogMapper
                .selectPage(
                        new Page<>(pageNo, pageSize),
                        new LambdaQueryWrapper<TMemberBalanceLog>()
                                .select(TMemberBalanceLog::getPayTime, TMemberBalanceLog::getTradeNo, TMemberBalanceLog::getTradeType, TMemberBalanceLog::getId,
                                        TMemberBalanceLog::getTips, TMemberBalanceLog::getMethod, TMemberBalanceLog::getMoney)
                                .eq(TMemberBalanceLog::getMId, getId(request))
                                .eq(TMemberBalanceLog::getStatus, CommonStatus.NORMAL.getType())
                                .orderByDesc(TMemberBalanceLog::getPayTime)
                );

        List<BalanceOrderByDate> collect = res
                .getRecords()
                .stream()
                .map(m ->
                        m.setShortTime(m.getPayTime().toLocalTime()).setDateTime(m.getPayTime().toLocalDate())
                                .setStrMoney(BalanceLogEnum.getByType(m.getTradeType()).getSymbol() + m.getMoney().stripTrailingZeros().toPlainString())
                )
                .collect(Collectors.groupingBy(TMemberBalanceLog::getDateTime))
                .entrySet()
                .stream()
                .map(m ->
                        new BalanceOrderByDate()
                                .setDate(DateUtils.getLocalDateStr(m.getKey()))
                                .setItem(m.getValue().stream().sorted(Comparator.comparing(TMemberBalanceLog::getShortTime).reversed()).collect(Collectors.toList()))
                ).sorted(Comparator.comparing(BalanceOrderByDate::getDate).reversed()).collect(Collectors.toList());

        return ApiResult.success(
                new PageResult<BalanceOrderByDate>()
                        .setCurrent(res.getCurrent())
                        .setPages(res.getPages())
                        .setSize(res.getSize())
                        .setTotal(res.getTotal())
                        .setRecords(collect)
        );
    }


    @ApiOperation("余额变更明细详情")
    @PostMapping("log/details")
    public ApiResult<TMemberBalanceLog> balanceLogDetails(@ApiParam("余额记录主键id") @RequestParam String logId) {

        TMemberBalanceLog log = memberBalanceLogMapper.selectById(logId);
        BalanceLogEnum type = BalanceLogEnum.getByType(log.getTradeType());
        Check.notNull(type, ExpCode.NOT_SUPPORT_TYPE);
        Check.notNull(log, ExpCode.DATA_ILLEGAL);

        Long mId = log.getMId();
        Long categoryId = null;

        switch (type) {
            case CONSUME:
            case CANCEL_ORDER: {
                //发单用户信息查询
                TPublishOrder publishOrder = publishOrderMapper.selectCategoryIdByOrderId(log.getTradeNo());
                if (publishOrder != null) {
                    mId = publishOrder.getMId();
                    categoryId = publishOrder.getCategoryId();
                }
                break;
            }
            case FINISH_ORDER: {
                C2cOrderItem item =
                        orderItemMapper
                                .selectList(
                                        new LambdaQueryWrapper<C2cOrderItem>()
                                                .select(C2cOrderItem::getTips)
                                                .eq(C2cOrderItem::getC2cOrderId, log.getTradeNo())
                                )
                                .stream()
                                .findFirst().orElse(new C2cOrderItem());
                C2cOrder order = c2cOrderMapper.selectOne(
                        new LambdaQueryWrapper<C2cOrder>()
                                .select(C2cOrder::getMId)
                                .eq(C2cOrder::getId, log.getTradeNo())
                );
                log.setTips(item.getTips());
                if (order != null)
                    mId = order.getMId();
                break;
            }

            case SPREAD_PROFIT: {
                //推广消息用户信息查询
                //查询同一订单号的其他消费情况
                TMemberBalanceLog consumeLog = memberBalanceLogMapper
                        .selectList(
                                new LambdaQueryWrapper<TMemberBalanceLog>()
                                        .select(TMemberBalanceLog::getMId, TMemberBalanceLog::getTradeType)
                                        .eq(TMemberBalanceLog::getTradeNo, log.getTradeNo())
                                        .eq(TMemberBalanceLog::getStatus, CommonStatus.NORMAL.getType())
                                        .ne(TMemberBalanceLog::getTradeType, log.getTradeType())
                        )
                        .stream()
                        .filter(f -> f.getTradeType().equals(BalanceLogEnum.FINISH_ORDER.getType()) || f.getTradeType().equals(BalanceLogEnum.DISPATCH_FINISH.getType()))
                        .findFirst()
                        .orElse(null);
                if (consumeLog != null)
                    mId = consumeLog.getMId();
                break;

            }
            case DISPATCH_PAY:
            case DISPATCH_CANCEL:
            case DISPATCH_FINISH: {
                TDispatchOrder order = dispatchOrderMapper.selectOne(
                        new LambdaQueryWrapper<TDispatchOrder>()
                                .select(TDispatchOrder::getCategory, TDispatchOrder::getServiceId,TDispatchOrder::getMId)
                                .eq(TDispatchOrder::getOrderId, log.getTradeNo())
                );
                log.setTips(order.getCategory());
                mId = Optional.ofNullable(order.getServiceId()).orElse(order.getMId());
                break;
            }

        }

        TMember member = memberMapper.selectOne(new LambdaQueryWrapper<TMember>()
                .select(TMember::getImgUrl, TMember::getNickName)
                .eq(TMember::getId, mId));
        TProductCategory category = Optional.ofNullable(categoryId).map(categoryService::getProductCategoryById).orElse(new TProductCategory());
        String tips = Optional.ofNullable(category.getCaption()).orElse(log.getTips());

        log.setTips(tips)
                .setImgUrl(StringUtils.isBlank(member.getImgUrl()) ? "" : ossConfig.getHostname() + "/" + member.getImgUrl())
                .setName(member.getNickName())
                .setFeeScale(
                        StringUtils.isBlank(log.getFeeScale()) ? null :
                                new BigDecimal(log.getFeeScale()).multiply(AppConst.b100).stripTrailingZeros().toPlainString());


        return ApiResult.success(log);
    }


    /**
     * 余额充值
     *
     * @return
     */
    @ApiOperation("余额充 值")
    @PostMapping("balance")
    public ApiResult<PrePayment> rechargeBalance(HttpServletRequest request,
                                                 @ApiParam("支付类型  1：微信 2支付宝") @RequestParam String payMethod,
                                                 @ApiParam("充值金额最小50") @RequestParam Integer rechargeMoney) {

        String rechargeNum = IdWorker.getIdStr();
        String payAmountByEnv = PayUtil.getPayAmountByEnv(componentFactory.getActiveProfile(), BigDecimal.valueOf(rechargeMoney));
        PaymentEnum payment = PaymentEnum.getByType(payMethod);

        Check.notNull(payment, ExpCode.PAY_NOT_SUPPORT);

        PrePayment prePayment =
                savePrePayInfo(
                        new PrePayParams(String.valueOf(rechargeMoney), rechargeNum, "rechargeYourBalance", payment.getBalance(), getId(request)),
                        getId(request),
                        payMethod,
                        componentFactory.getPayInstance(payment));

        return ApiResult.success(prePayment);
    }


    /**
     * 会员余额充值 预支付信息保存
     *
     * @param prePayParams
     * @param mId
     * @param payMethod
     * @param paymentInterface
     * @return
     */
    private PrePayment savePrePayInfo(PrePayParams prePayParams,
                                      String mId,
                                      String payMethod,
                                      PrePaymentInterface paymentInterface) {
        TMemberBalanceLog log = new TMemberBalanceLog();
        PrePayment prePayment = paymentInterface.prePayment(prePayParams);
        log
                .setTradeNo(prePayParams.getOrderId())
                .setMId(Long.parseLong(mId))
                .setMoney(new BigDecimal(prePayParams.getMoney()))
                .setMethod(Integer.parseInt(payMethod))
                .setTradeType(BalanceLogEnum.RECHARGE.getType());

        if (prePayment instanceof WxPrePayment)
            log.setPrePayId(((WxPrePayment) prePayment).getPrePayId());

        Assert.state(memberBalanceLogMapper.insert(log) == 1, "save rechargeBalance  prepay info exception");

        return prePayment;
    }


}
